<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="/Public/js/three.min.js"></script>
    <script src="/Public/js/three_shaders.js"></script>
    <script src="/Public/js/OrbitControls.js"></script>
    <script src="/Public/js/jquery-3.7.1.min.js"></script>
    <script src="/Public/js/geotiff.js"></script>
    <script src="../deepSeekTest.js"></script>
    <style>
        body {
            margin: 0;
            overflow: hidden;
            background: #1a1a2e;
            font-family: Arial, sans-serif;
        }
    </style>
</head>

<body>

    <script type="module">
        const scene = new THREE.Scene();
        scene.background = new THREE.Color(0x1a1a2e);
        const camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 10000);
        camera.position.set(4, 3.5, 3);
        const renderer = new THREE.WebGLRenderer({ antialias: true });
        renderer.setSize(window.innerWidth, window.innerHeight);
        document.body.appendChild(renderer.domElement);
        const ambientLight = new THREE.AmbientLight(0x404040);
        scene.add(ambientLight);
        const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
        directionalLight.position.set(1, 1, 1);
        scene.add(directionalLight);
        const controls = new THREE.OrbitControls(camera, renderer.domElement);
        controls.enableDamping = true;

        //-------------------------------------

        const file = '/Public/imgs/dem/terrain2.tif';
        const res = await fetch(file)
        const arrayBuffer = await res.arrayBuffer();
        const tiff = await GeoTIFF.fromArrayBuffer(arrayBuffer)
        const image = await tiff.getImage()
        const rasters = await image.readRasters()
        const width = image.getWidth()
        const height = image.getHeight()
        const elevationData = new Float32Array(rasters[0])
        const geometry = new THREE.PlaneGeometry(5, 5 * height / width, width - 1, height - 1)
        let maxElevation = -Infinity
        for (let i = 0; i < elevationData.length; i++) {
            if (elevationData[i] > maxElevation) {
                maxElevation = elevationData[i]
            }
        }
        let minElevation = Infinity
        for (let i = 0; i < elevationData.length; i++) {
            const num = elevationData[i]
            if (num !== 0 && num < minElevation) {
                minElevation = num
            }
        }
        const positions = geometry.attributes.position.array
        for (let i = 0; i < elevationData.length; i++) {
            if (maxElevation == minElevation) {
                positions[i * 3 + 2] = 0
            }
            else {
                positions[i * 3 + 2] = (elevationData[i] - minElevation) / (maxElevation - minElevation)
            }
        }
        geometry.attributes.position.needsUpdate = true
        geometry.computeVertexNormals()

        const base_mesh_material = new THREE.MeshBasicMaterial({
            color: '#ff0000',
            wireframe: true,
            transparent: true,
            opacity: 0.2
        })
        const base_mesh = new THREE.Mesh(geometry, base_mesh_material)
        base_mesh.rotateX(-Math.PI / 2);
        scene.add(base_mesh)

        const vs1 = `
            varying vec2 vUv;
            varying vec3 vWorldPosition;
            void main() {
                vUv = uv;
                vec4 worldPosition = modelMatrix * vec4(position, 1.0);
                vWorldPosition = worldPosition.xyz;
                gl_Position = projectionMatrix * viewMatrix * worldPosition;
            }
        `

        const fs1 = `
            uniform vec3 triangleA;
            uniform vec3 triangleB;
            uniform vec3 triangleC;
            uniform bool showTriangle;
            varying vec3 vWorldPosition;
            
            bool pointInTriangle(vec3 p, vec3 a, vec3 b, vec3 c) {
                vec2 p2 = p.xz;
                vec2 a2 = a.xz;
                vec2 b2 = b.xz;
                vec2 c2 = c.xz;
                
                vec2 v0 = c2 - a2;
                vec2 v1 = b2 - a2;
                vec2 v2 = p2 - a2;
                
                float dot00 = dot(v0, v0);
                float dot01 = dot(v0, v1);
                float dot02 = dot(v0, v2);
                float dot11 = dot(v1, v1);
                float dot12 = dot(v1, v2);
                
                float invDenom = 1.0 / (dot00 * dot11 - dot01 * dot01);
                float u = (dot11 * dot02 - dot01 * dot12) * invDenom;
                float v = (dot00 * dot12 - dot01 * dot02) * invDenom;
                
                return (u >= 0.0) && (v >= 0.0) && (u + v <= 1.001); // 加一点容差
            }
            
            void main() {
                gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);
                
                if (!showTriangle) {
                    return;
                }

                if (pointInTriangle(vWorldPosition, triangleA, triangleB, triangleC)) {
                    gl_FragColor = vec4(1.0, 1.0, 0.0, 0.8);
                }
            }
        `

        const click_geometry = base_mesh.geometry
        const click_material = new THREE.ShaderMaterial({
            vertexShader: vs1,
            fragmentShader: fs1,
            side: THREE.DoubleSide,
            uniforms: {
                triangleA: { value: new THREE.Vector3() },
                triangleB: { value: new THREE.Vector3() },
                triangleC: { value: new THREE.Vector3() },
                showTriangle: { value: false }
            },
            transparent: true,
        })

        const click_mesh = new THREE.Mesh(geometry, click_material)
        click_mesh.rotateX(- Math.PI / 2)
        scene.add(click_mesh)

        const raycaster = new THREE.Raycaster()
        const mouse = new THREE.Vector2()
        function onMouseClick(event) {
            mouse.x = (event.clientX / window.innerWidth) * 2 - 1
            mouse.y = -(event.clientY / window.innerHeight) * 2 + 1
            raycaster.setFromCamera(mouse, camera)
            const intersects = raycaster.intersectObject(base_mesh)
            if (intersects.length > 0) {
                const intersect = intersects[0]
                const face = intersect.face
                if (face) {
                    const aIndex = face.a
                    const bIndex = face.b
                    const cIndex = face.c
                    const positions = geometry.attributes.position.array
                    const getVertexPosition = (index) => {
                        const x = positions[index * 3]
                        const y = positions[index * 3 + 1]
                        const z = positions[index * 3 + 2]
                        return new THREE.Vector3(x, y, z)
                    }
                    const vertexA = getVertexPosition(aIndex)
                    const vertexB = getVertexPosition(bIndex)
                    const vertexC = getVertexPosition(cIndex)
                    vertexA.applyMatrix4(base_mesh.matrixWorld)
                    vertexB.applyMatrix4(base_mesh.matrixWorld)
                    vertexC.applyMatrix4(base_mesh.matrixWorld)
                    click_material.uniforms.triangleA.value.copy(vertexA)
                    click_material.uniforms.triangleB.value.copy(vertexB)
                    click_material.uniforms.triangleC.value.copy(vertexC)
                    click_material.uniforms.showTriangle.value = true
                }
            }
        }
        window.addEventListener('click', onMouseClick, false)

        //-------------------------------------

        function animate() {
            requestAnimationFrame(animate);
            controls.update();
            renderer.render(scene, camera);
        }

        // 启动动画
        animate();

        // 窗口大小调整
        window.addEventListener('resize', () => {
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth, window.innerHeight);
        });
    </script>
</body>

</html>